package com.example.rule.util;


import com.example.rule.condition.factory.AbstractConditionFactory;
import com.example.rule.condition.factory.CommonFactory;
import com.example.rule.constant.RuleConstant;
import com.example.rule.core.Condition;
import com.example.rule.core.Rule;
import com.example.rule.db.entity.PymtRule;
import com.example.rule.db.entity.PymtRuleOperator;
import com.example.rule.db.entity.PymtRuleType;
import com.example.rule.expression.factory.AbstractRepFactory;
import com.example.rule.expression.factory.NameFactory;
import com.example.rule.expression.factory.OneTimeFactory;
import com.example.rule.expression.factory.TodayFactory;
import com.example.rule.expression.factory.WhereTimeFactory;
import com.example.rule.rule.BasicRule;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Jason - Chusifeng
 * @version 1.0.0
 * @className CacheUtil.java
 * @packageName com.example.rule.util
 * @createTime 2022年10月10日 09:29:26
 * @description cache rule
 */
@Slf4j
@SuppressWarnings({"unchecked"})
public class CacheUtil {

    private static Cache<String, List> CACHE;

    public static void init() {
        CACHE = CacheBuilder.<String, List<Condition>>
                        newBuilder().
                maximumSize(1000).
                softValues().
                removalListener(new CacheListener()).
                build(new CacheLoader());
    }

    public static void cacheRule(List<PymtRule> ruleList) {
        if (CollectionUtils.isEmpty(ruleList)) {
            return;
        }

        //缓存condition factory
        //去空
        List<String> conStrs = ruleList.stream().map(rule ->rule.getConditionName().trim()).distinct().collect(Collectors.toList());
        AbstractConditionFactory factory;
        for (String commonName : conStrs) {
            if ("common".equals(commonName)) {
                factory = new CommonFactory();
            } else {
                factory = null;
            }
            RuleConstant.CONFIG_COND.put(commonName, factory);
        }
        List<Rule> result = new ArrayList<>(ruleList.size());
        for (PymtRule pymtRule : ruleList) {
            //禁用的不参加
            if (pymtRule.getStatus() != 0) {
                continue;
            }
            //第一个条件操作符不应该是空
            if (StringUtils.isBlank(pymtRule.getOperator1())) {
                continue;
            }
            Rule rule = null;
            try {
                rule = BasicRule.createRule(pymtRule);
            } catch (Exception e) {
                log.error("create rule error,", e);
            }
            if (null != rule) {
                result.add(rule);
            }
        }
        CACHE.put(RuleConstant.RULE_CACHE_KEY, result);
    }

    public static List<Rule> getRules() {
        return CACHE.getIfPresent(RuleConstant.RULE_CACHE_KEY);
    }

    public static List<PymtRuleType> getRuleTypes() {
        return CACHE.getIfPresent(RuleConstant.RULE_TYPE_CACHE_KEY);
    }

    public static List<PymtRuleOperator> getRuleOperators() {
        return CACHE.getIfPresent(RuleConstant.RULE_OPERATOR_CACHE_KEY);
    }
    /**
     * @author Jason - Chusifeng
     * @Description
     * @version: v1.8.0
     * @date 13:35 2022/10/12
     * @param
     * @return 缓存 rule type 和 对应的expression factory
     **/
    public static void cacheType(List<PymtRuleType> typeList) {
        //缓存rule
        CACHE.put(RuleConstant.RULE_TYPE_CACHE_KEY, typeList);
        if (!CollectionUtils.isEmpty(typeList)) {
            //缓存rule对应的生成expression的Representation工厂
            List<Integer> idList = typeList.stream().map(PymtRuleType::getValue).distinct().collect(Collectors.toList());
            for (Integer id : idList) {
                AbstractRepFactory factory;
                switch (id) {
                    case 1:
                        factory = new TodayFactory();
                        break;
                    case 2:
                        factory = new OneTimeFactory();
                        break;
                    case 3:
                        factory = new WhereTimeFactory();
                        break;
                    case 4:
                        factory = new NameFactory();
                        break;
                    default:
                        factory = null;
                }
                RuleConstant.CONFIG_REP.put(id, factory);
            }
        }
    }

    public static void cacheOperator(List<PymtRuleOperator> operatorList) {
        CACHE.put(RuleConstant.RULE_OPERATOR_CACHE_KEY, operatorList);
    }

//    public static void main(String[] args) {
//        PymtRule rule = new PymtRule();
//        rule.setConnector(SelectorEnum.AND);
//        rule.setChargeType("1");
//        rule.setChargeValue("0.001");
//        rule.setOperator1("<=");
//        rule.setValue1("300000");
//        rule.setOperator2(">");
//        rule.setValue2("10000");
//        rule.setProirity(1);
//        rule.setStatus(0);
//        rule.setType("1");
//        rule.setCreatedAt(ZonedDateTime.now());
//        rule.setCreatedBy("system");
//        rule.setUpdatedAt(ZonedDateTime.now());
//        rule.setUpdatedBy("system");
//
//        init();
//        cache(Collections.singletonList(rule));
//        List<Rule> ruleList = CACHE.getIfPresent(Constant.RULE_CACHE_KEY);
//
//        Rules rules = new Rules(ruleList);
//
//        Facts facts = new Facts();
//        TodayFact fact = new TodayFact();
//        fact.setTotal(new BigDecimal("3000"));
//        fact.setMoney(new BigDecimal("1000"));
//        facts.addFact(fact);
//        RuleEngine engine  = new RuleEngine();
//        //如果通过就跳过后续的，设置此选项最大值不生效
//        engine.setSkipIfOnePass(true);
//        //发现异常直接终止
//        engine.setIfExceptionThrow(true);
//        //取最大值
//        engine.setTakeMax(false);
//        //执行操作
//        BigDecimal result = engine.doExpress(facts,rules);
//        System.out.println(result);
//    }
}

